#include "localmethod.hpp"
#include <qmetaobject.h>
#include <qthread.h>
#include <qdebug.h>
#include <qobjectdefs.h>
namespace localObject {
LocalMethod::LocalMethod(QObject *parent) : QObject(parent)
{

}
QStringList LocalMethod::methods()
{
    QStringList list;
    const QMetaObject *mo = metaObject ();
    for (int i = 0; i < mo->methodCount(); ++i) {
        QMetaMethod md = mo->method(i);
        const QString signature = QString::fromLatin1(md.methodSignature());
        if(md.methodType ()==QMetaMethod::Slot ||
                md.methodType ()==QMetaMethod::Method)
        {
            if(signature == "deleteLater()"
                    || signature == "deleteLater()"
                    || signature == "_q_reregisterTimers(void*)"
                    )
            {
                continue;
            }
            list<<signature;
        }
    }
    return list;
}

QList<int> LocalMethod::getParamTypes(QString methodname)
{
    int index = metaObject ()->indexOfMethod (methodname.toLatin1 ());
    QMetaMethod md = metaObject ()->method (index);
    QList<int> list;
    for(int i=0;i<md.parameterCount ();i++)
    {
        list<<md.parameterType (i);
    }
    return list;
}

QStringList LocalMethod::getParamDBusTypes(QString methodname)
{
    auto types = getParamTypes(methodname);
    QStringList dbustypes;
    for(int c:types)
    {
        if(c ==QMetaType::QByteArray)
        {
            dbustypes.append ("ay");
        }else if(c ==QMetaType::Bool)
        {
            dbustypes.append ("b");
        }else if(c ==QMetaType::UChar)
        {
            dbustypes.append ("y");
        }else if(c ==QMetaType::Char)
        {
            dbustypes.append ("y");
        }else if(c ==QMetaType::UShort)
        {
            dbustypes.append ("q");
        }else if(c ==QMetaType::UInt)
        {
            dbustypes.append ("u");
        }else if(c ==QMetaType::ULongLong
                 || c ==QMetaType::ULong
                 )
        {
            dbustypes.append ("t");
        }else if(c ==QMetaType::Short)
        {
            dbustypes.append ("n");
        }else if(c ==QMetaType::Double)
        {
            dbustypes.append ("d");
        }else if(c ==QMetaType::Int)
        {
            dbustypes.append ("i");
        }else if(c ==QMetaType::LongLong
                 || c ==QMetaType::Long)
        {
            dbustypes.append ("t");
        }else if(c ==QMetaType::QString)
        {
            dbustypes.append ("s");
        }else
        {
//            qDebug()<<QMetaType::typeName (c)<<QMetaType::sizeOf (c);
        }
    }
    return dbustypes;
}

QStringList LocalMethod::getParamNames(QString methodname)
{
    int index = metaObject ()->indexOfMethod (methodname.toLatin1 ());
    QMetaMethod md = metaObject ()->method (index);
    QStringList list;
    for(int i=0;i<md.parameterCount ();i++)
    {
        list<<md.parameterNames ().at (i);
    }
    return list;
}

QVariant LocalMethod::callMethod(const QString &methodname,QVariantList args,bool *ok)
{
    int index = metaObject ()->indexOfMethod (methodname.toLatin1 ());
    QMetaMethod md = metaObject ()->method (index);
    int i=0;
    QGenericArgument Argument[10];
    for(int i=0;i<10;i++)
    {


        if(i<args.count ())
        {
            uint dd= args.at (i).toUInt ();
            void * data = QMetaType::create(md.parameterType (i),&dd);
            const char* name = QMetaType::typeName (md.parameterType (i));
            QGenericArgument arg0{name, data};
            Argument[i] = arg0;
        }else
        {
            Argument[i] = QGenericArgument(Q_NULLPTR);
        }
    }
    if(md.returnType () == QMetaType::Void)
    {
        bool bret = md.invoke(this,Qt::DirectConnection,Argument[0],Argument[1],Argument[2],Argument[3],
                Argument[4],Argument[5],Argument[6],Argument[7],Argument[8],Argument[9]);
        if(ok!=NULL)
        {
            *ok = bret;
        }
        return QVariant();
    }else
    {
        void *data = QMetaType::create (md.returnType ());
        const char *name = QMetaType::typeName(md.returnType ());
        QGenericReturnArgument returnValue{name, data};
        bool bret = md.invoke (this,Qt::DirectConnection,returnValue,Argument[0],Argument[1],Argument[2],Argument[3],
                Argument[4],Argument[5],Argument[6],Argument[7],Argument[8],Argument[9]);
        if(ok!=NULL)
        {
            *ok = bret;
        }
        if(bret)
        {
            QVariant vret(md.returnType (),data);
            QMetaType::destroy(md.returnType (),data);
            return vret;
        }else
        {
            return QVariant();
        }
    }
}

void LocalMethod::sleep(uint s)
{
    QThread::sleep (s);
}

void LocalMethod::msleep(uint ms)
{
    QThread::msleep ((unsigned long)ms);
}

void LocalMethod::usleep(uint us)
{
    QThread::usleep (us);
}
}
localObject::LocalMethod &localObj()
{
    static localObject::LocalMethod g_LocalMethod(Q_NULLPTR);
    return g_LocalMethod;
}
